#pragma once

#include <cassert>

#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#include <map>

#include "util/fs.h"

#include "convert-route.h"
#include "uri-path.h"
#include "index-item.h"


namespace book
{

// 图书的索引树
// 维护整个图书的全部各层的索引信息
class IndexTree
{
public:

    class NotDirError : public std::logic_error
    {
    public:
        NotDirError(const char *msg) : std::logic_error(msg) {}
    };

    class Node
    {
    public:

        bool isRoot() const {
            return parent_ == nullptr;
        }

        bool isLeaf() const {
            return children_.empty();
        }

        std::string fsPath() const;

        std::string uriPath() const;

        const IndexItem &data() const {
            return data_;
        }

        IndexItem &data() {
            return data_;
        }

        void setData(IndexItem &&data) {
            data_ = std::move(data);
        }

        const std::vector<Node *> &children() const {
            return children_;
        }

        const Node *prev() const {
            return prev_;
        }

        // 找当前节点前最近的文章节点
        const Node *prevArticle() const;

        const Node *next() const {
            return next_;
        }

        // 找当前节点后最近的文章节点
        const Node *nextArticle() const;

        const Node *findChildByUriName(const std::string_view &uriName) const {
            auto it = uriNameToChild_.find(uriName);
            if (it != uriNameToChild_.end()) {
                return it->second;
            }
            return nullptr;
        }

    private:

        // 内存管理较复杂，只能由 IndexTree 构造和释放
        Node() {}

        // 内存管理较复杂，只能由 IndexTree 构造和释放
        ~Node();

        void addChildNode(Node *node);

        // 只进行单层节点的移动
        void moveForRootNode(Node &b) {
            assert(isRoot() && b.isRoot());
            children_ = std::move(b.children_);
            for (Node *child : children_) {
                child->parent_ = this;
            }
            dirEntryNameToChild_ = std::move(b.dirEntryNameToChild_);
            uriNameToChild_ = std::move(b.uriNameToChild_);
            prev_ = b.prev_;
            b.prev_ = nullptr;
            next_ = b.next_;
            b.next_ = nullptr;
            data_ = std::move(b.data_);
        }

    private:
        // 维护子节点的顺序
        // 考虑到文件名或URI名重名，用children_成员来管理子节点的生命周期
        std::vector<Node *> children_;

        // 维护从文件名或文件夹名称到子节点的映射
        // map的键直接用children_中的Node节点中的字符串的视图
        std::map<std::string_view, Node *> dirEntryNameToChild_;

        // 维护从URI名到子节点的映射
        // map的键直接用children_中的Node节点中的字符串的视图
        std::map<std::string_view, Node *> uriNameToChild_;

        // 父节点
        Node *parent_ = nullptr;

        // 对整个索引树遍历时的前驱节点
        Node *prev_ = nullptr;

        // 对整个索引树遍历时的后继节点
        Node *next_ = nullptr;

        IndexItem data_;

        friend class IndexTree;
    };

    class NewNode
    {
    public:
        NewNode() : ptr_(new book::IndexTree::Node) {}

        ~NewNode() {
            if (ptr_) {
                delete ptr_;
                ptr_ = nullptr;
            }
        }

        book::IndexTree::Node *operator->() const {
            return ptr_;
        }

        book::IndexTree::Node *get() const {
            return ptr_;
        }

        book::IndexTree::Node *take() {
            book::IndexTree::Node *ptr = ptr_;
            ptr_ = nullptr;
            return ptr;
        }

    private:
        book::IndexTree::Node *ptr_ = nullptr;
    };

    IndexTree();

    IndexTree(const fs::path &dir);

    IndexTree(const IndexTree &) = delete;

    IndexTree(IndexTree &&b) noexcept
        : title_(std::move(b.title_))
        , rootDir_(std::move(b.rootDir_)) {
        root_.moveForRootNode(b.root_);
    }

    ~IndexTree();

    IndexTree &operator=(const IndexTree &) = delete;

    IndexTree &operator=(IndexTree &&b) noexcept {
        if (this != &b) {
            title_ = std::move(title_);
            rootDir_ = std::move(b.rootDir_);
            root_.moveForRootNode(b.root_);
        }
        return *this;
    }

    operator bool() const {
        return !root_.children_.empty();
    }

    // 把URI路径转换为文件系统路径
    fs::path conv(const std::string_view &uriPath);

    const Node *root() const {
        return &root_;
    }

    const fs::path &rootDir() const {
        return rootDir_;
    }

    // 返回完全匹配指定路径的节点
    const Node *findNodeByUri(const std::string &uri) const;

    // 返回离指定路径最近的父节点或祖先节点
    const Node *findClosetExistingNodeByUri(const std::string &uri) const;

private:
    const std::string &title() const {
        return title_;
    }

    void buildDir(Node *dirNode, const fs::path &dir) const;

    std::vector<IndexItem> parseIndexFile(const fs::path &indexFile) const;

    class ClueHelper
    {
    public:
        ClueHelper(Node &root) : root_(root) {}

        void clue() {
            for (Node *node : root_.children_) {
                clue(node);
            }
        }

    private:
        void clue(Node *node);

    private:
        Node &root_;
        Node *prev_ = nullptr;
    };

    // 线索化
    void clue();

private:
    std::string title_;
    fs::path rootDir_;
    Node root_;
};

} // namespace book
